# External Modules
import pygame

# Project Modules
from CWeapon import CWeapon
from CMap import CMap
from CHUD import CHUD
from CTextureManager import CTextureManager

class CPlayer(object):
    """ Holds player data and sprite information """
    
    LEFT = 0
    RIGHT = 1
    UP = 2
    DOWN = 3

    ATTACK_TIME_UP =  4
    
    def __init__(self , spriteSheet ):
        """ Create the player object, binding the sprite sheet image and setting the starting x , y coordinates. """
        
        # Sprite
        if( CTextureManager.IsLoadedTexture("Player") == False):
            self.mSpriteSheet = CTextureManager.LoadTexture( spriteSheet , "Player")
        else:
            self.mSpriteSheet = CTextureManager.GetTexture("Player")
            
        self.mSpriteRect = pygame.Rect( ( 0 , 0 ) , ( 16 , 16 ) )
        
        self.mXPos = 0
        self.mYPos = 0
        
        self.mCurrentDirection = self.DOWN
        
        # Variables to handle attacking/attack animation timing
        self.mIsAttacking = False
        self.mStartedAttacking = 0
        
        # The map we are currently in. We set this with self.SetCurrentMap( map ).
        self.mCurrentMap = None
        
        # Bind our starter weapon
        self.mCurrentWeapon = CWeapon( "Rustarch" , 1 , 10.0 )
        
        # Set our initial gold
        self.mCurrentGold = 0
        
        # Set our initial health
        self.mCurrentHealth = 10
        
        # Boss defeated flag
        self.mDefeatedBoss = False
        
        # Update HUD
        self.UpdateCharacterStatsHUD()
            
    def move(self , direction ):
        """ Move the player one unit in a given direction. ( UP , DOWN , LEFT , RIGHT ) """
        
        # For the given direction we move the player 16 pixels and orient our sprite to the current heading using our rect.
        if( direction == self.LEFT ):
            self.mXPos -= 16
            self.mSpriteRect.left = 48
            self.mCurrentDirection = self.LEFT
        elif( direction == self.RIGHT ):
            self.mXPos += 16
            self.mSpriteRect.left = 32
            self.mCurrentDirection = self.RIGHT
        elif( direction == self.UP ):
            self.mYPos -= 16
            self.mSpriteRect.left = 16
            self.mCurrentDirection = self.UP
        elif( direction == self.DOWN ):
            self.mYPos += 16
            self.mSpriteRect.left = 0
            self.mCurrentDirection = self.DOWN
        else:
            return
        
    def draw(self , inScreen):
        """ Draw our character as well as any attachments they may have. Currently the only supported attachment is a weapon. """ 
        
        # Check our animation times
        if( self.mIsAttacking == True and ( pygame.time.get_ticks() - self.mStartedAttacking >= 150 )):
            self.mIsAttacking = False
            self.mStartedAttacking = 0
        
        
        if( self.mCurrentDirection == self.DOWN ):
            # Draw our character first, then our weapon with the correct offset.
            inScreen.blit( self.mSpriteSheet , ( self.mXPos , self.mYPos ) , self.mSpriteRect )
            # Draw Weapon
            self.mCurrentWeapon.rotate(0)
            if( self.mIsAttacking ) : self.mCurrentWeapon.draw( inScreen , self.mXPos+8 , self.mYPos+13)
        elif( self.mCurrentDirection == self.UP ):
            # Draw weapon first as character occludes weapon
            self.mCurrentWeapon.rotate(180)
            if( self.mIsAttacking ) : self.mCurrentWeapon.draw( inScreen , self.mXPos , self.mYPos-9 )
            inScreen.blit( self.mSpriteSheet , ( self.mXPos , self.mYPos ) , self.mSpriteRect )
        elif( self.mCurrentDirection == self.RIGHT ):
            self.mCurrentWeapon.rotate(90)
            if( self.mIsAttacking ) : self.mCurrentWeapon.draw( inScreen , self.mXPos+10 , self.mYPos+9 )
            inScreen.blit( self.mSpriteSheet , ( self.mXPos , self.mYPos ) , self.mSpriteRect )
        elif( self.mCurrentDirection == self.LEFT ):
            self.mCurrentWeapon.rotate(270)
            if( self.mIsAttacking ) : self.mCurrentWeapon.draw( inScreen , self.mXPos-7 , self.mYPos+9 )
            inScreen.blit( self.mSpriteSheet , ( self.mXPos , self.mYPos ) , self.mSpriteRect )
             
    def setDirection( self , direction ):
        """ Sets our player's direction without moving them. """
        if( direction == self.LEFT ):
            self.mSpriteRect.left = 48
            self.mCurrentDirection = self.LEFT
        elif( direction == self.RIGHT ):
            self.mSpriteRect.left = 32
            self.mCurrentDirection = self.RIGHT
        elif( direction == self.UP ):
            self.mSpriteRect.left = 16
            self.mCurrentDirection = self.UP
        elif( direction == self.DOWN ):
            self.mSpriteRect.left = 0
            self.mCurrentDirection = self.DOWN
        else:
            return
        
    def Attack(self):
        """ Attack one square in front of the player with the current weapon. """
        
        # RETURN: If we are attacking we shall not attack again
        if( self.mIsAttacking == True):
            return
            
        # Set up attack animation
        self.mCurrentWeapon.playSound()
        self.mIsAttacking = True
        self.mStartedAttacking = pygame.time.get_ticks()  
        
        # Check to see if we've hit anything and if so, kill it.
        pos = self.GetWorldPos()
        e = None
    
        if( self.mCurrentDirection == self.LEFT ):
            e = self.mCurrentMap.GetEnemyInSpace( (pos[0]-1 , pos[1] ) )
            
        elif( self.mCurrentDirection == self.RIGHT ):
            e = self.mCurrentMap.GetEnemyInSpace( (pos[0]+1 , pos[1] ) )
            
        elif( self.mCurrentDirection == self.UP ):
            e = self.mCurrentMap.GetEnemyInSpace( (pos[0] , pos[1]-1 ) )
            
        elif( self.mCurrentDirection == self.DOWN ):
            e = self.mCurrentMap.GetEnemyInSpace( (pos[0] , pos[1]+1 ) )
            
        # Kill the enemy and log the kill    
        if( e != None ): 
            #CHUD.LogMessage("Player killed [" + e.GetName() + "]!" )
            e.TakeDamage( self.mCurrentWeapon.mAttackDamage )

    def TakeDamage( self , d ):
        """ Player take damages of amount d. """
        # Trigger damage anim or trigger death
        
        self.mCurrentHealth -= d
        self.UpdateCharacterStatsHUD()
        
    def GetWorldPos(self):
        """ Get the world position tuple of the player. Useful for handling collisions within the tile set etc. """
        return ( self.mXPos/16 , self.mYPos/16 )
    
    def SetWorldPos(self , ( x , y ) ):
        """ Set the players position via world coordinates. """
        self.mXPos = x * 16
        self.mYPos = y * 16
        
    def SetCurrentMap(self , map):
        """ Give the player a reference to the current map. """
        self.mCurrentMap = map
        
    def GiveWeapon(self , name , atk ):
        """ Give the player a new weapon with specified name and attack damage. """           
        self.mCurrentWeapon = CWeapon( name , atk , 10.0 )
            
    def UpdateCharacterStatsHUD(self):
        """ This will update all stats ( gold , weapon , health ) related to the character in the hud. """
        CHUD.ChangeWeaponStat( self.mCurrentWeapon.mName , self.mCurrentWeapon.mAttackDamage )
        CHUD.ChangeStat( CHUD.STAT_GOLD , self.mCurrentGold )
        CHUD.ChangeStat( CHUD.STAT_HEALTH , self.mCurrentHealth )